package org.fixed.dubboconsumer.core.util;


import org.fixed.dubboconsumer.entity.CallRequest;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.ReferenceConfig;
import com.alibaba.dubbo.config.RegistryConfig;
import com.alibaba.dubbo.rpc.service.GenericService;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.CollectionUtils;
import org.springside.modules.utils.mapper.JsonMapper;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

class Call {

    private final static Logger logger = LogManager.getLogger(Call.class);

    private String registryAddress;

    private String remoteUrl;

    // 当前应用的信息
    private ApplicationConfig application = new ApplicationConfig();
    // 注册中心信息缓存
    private Map<String, RegistryConfig> registryConfigCache = new ConcurrentHashMap<>();

    // 各个业务方的ReferenceConfig缓存
    private Map<String, ReferenceConfig> referenceCache = new ConcurrentHashMap<>();

    public Call(String registryAddress, String remoteUrl, String key) {
        this.registryAddress = registryAddress;
        this.remoteUrl = remoteUrl;
        application.setName("dubbo_crm_provider" + key);
    }

    /**
     * 执行dubbo 方法
     *
     * @param request
     * @param method
     * @return
     */
    public Object invoke(CallRequest request, Method method) {
        ReferenceConfig reference = getReferenceConfig(request, null);

        if (null != reference) {
            //获取 代理service
            GenericService genericService = (GenericService) reference.get();
            if (genericService == null) {
                throw new RuntimeException("Dubbo GenericService 不存在:" + request.getInterfaceClass().getName());
            }
            //参数列表
            Object[] paramObject = null;
            if (!CollectionUtils.isEmpty(request.getParam())) {
                paramObject = request.getParam().toArray(new Object[request.getParam().size()]);
            }
            //参数类型
            String[] argsType = null;
            if (ArrayUtils.isNotEmpty(method.getParameterTypes())) {
                argsType = new String[method.getParameterTypes().length];
                for (int i = 0; i < method.getParameterTypes().length; i++) {
                    argsType[i] = method.getParameterTypes()[i].getTypeName();
                }
            }
            //执行
            logger.info("genericService开始执行");
            Object resultParam = genericService.$invoke(method.getName(), argsType, paramObject);
            logger.info("genericService完成，结果:{}", resultParam);
            Object result = null;
            if (null != method.getReturnType()) {
                result = JsonMapper.nonEmptyMapper().fromJson(JsonMapper.nonEmptyMapper().toJson(resultParam), method.getReturnType());
            }
            return result;
        }
        return null;
    }

    /**
     * @param request
     * @param group
     * @return
     */
    private ReferenceConfig getReferenceConfig(CallRequest request, String group) {
        String referenceKey = request.getInterfaceClass().getSimpleName() + StringUtils.trimToEmpty(request.getVersion());
        ReferenceConfig referenceConfig = referenceCache.get(referenceKey);

        if (null == referenceConfig) {
            referenceConfig = new ReferenceConfig<>();
            referenceConfig.setApplication(application);
            referenceConfig.setRegistry(getRegistryConfig(registryAddress, group, request.getVersion()));
            referenceConfig.setInterface(request.getInterfaceClass());
            referenceConfig.setTimeout(60000);
            if (StringUtils.isNotEmpty(request.getVersion())) {
                referenceConfig.setVersion(request.getVersion());
            }
            referenceConfig.setGeneric(true);
            if (StringUtils.isNotEmpty(remoteUrl)) {
                referenceConfig.setUrl("dubbo://" + remoteUrl);
            }
            referenceCache.put(referenceKey, referenceConfig);
        }
        return referenceConfig;
    }

    /**
     * 获取注册中心信息
     *
     * @param address zk注册地址
     * @param group   dubbo服务所在的组
     * @return
     */
    private RegistryConfig getRegistryConfig(String address, String group, String version) {
        String key = address + "-" + group + "-" + version;
        RegistryConfig registryConfig = registryConfigCache.get(key);
        if (null == registryConfig) {
            registryConfig = new RegistryConfig();
            if (StringUtils.isNotEmpty(address)) {
                registryConfig.setAddress(address);
            }
            if (StringUtils.isNotEmpty(version)) {
                registryConfig.setVersion(version);
            }
            if (StringUtils.isNotEmpty(group)) {
                registryConfig.setGroup(group);
            }
            registryConfigCache.put(key, registryConfig);
        }
        return registryConfig;
    }
}